package cn.org.donald.filter;

import cn.org.donald.base.HttpResult;
import cn.org.donald.security.body.AuthorizationInfo;
import cn.org.donald.security.exception.AuthenticationException;
import cn.org.donald.security.exception.AuthorizationException;
import cn.org.donald.security.filter.DefaultDonaldAccessFilter;
import cn.org.donald.security.util.ApplicationContextUtil;
import cn.org.donald.util.CryPtoUtil;
import com.auth0.jwt.exceptions.*;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.data.redis.core.RedisTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author : Donald
 * @since : 2021/3/16 16:20
 */
public class MyAccessFilter extends DefaultDonaldAccessFilter {


    @Override
    protected boolean doAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String authorization = request.getHeader("authorization");

        // 如果authorization 为空,直接返回抛出异常(返回false的话会重定向到指定的登录地址), 如果配置了security框架的不拦截路径,不会走这里就直接放行了
        if (authorization == null || "".equals(authorization)) {
            throw new AuthenticationException(HttpResult.fail(401,"身份认证失败请重新登录!"));
        }
        try {
            // 验证通过则返回true
            DecodedJWT decodedJWT = CryPtoUtil.verifyAuthorization(authorization);
        } catch (AlgorithmMismatchException exception) {
            exception.printStackTrace();
            throw new AuthenticationException("算法不匹配异常");
        } catch (SignatureVerificationException exception) {
            exception.printStackTrace();
            throw new AuthenticationException("签名验证异常");
        } catch (TokenExpiredException exception) {
            exception.printStackTrace();
            throw new AuthenticationException("token过期异常");
        } catch (InvalidClaimException exception) {
            exception.printStackTrace();
            throw new AuthenticationException("无效Claim异常");
        } catch (JWTDecodeException exception) {
            exception.printStackTrace();
            throw new AuthenticationException("JWT解码异常");
        } catch (JWTVerificationException exception) {
            exception.printStackTrace();
            throw new AuthenticationException("JWT验证异常");
        }
        // 通过返回true,向上抛异常或返回false为拦截,默认false会重定向登录页面,不建议返回false,直接抛异常可以抛出异常信息体.
        return true;
    }

    @Override
    protected AuthorizationInfo authorizationInfo(HttpServletRequest request, HttpServletResponse response) {
        AuthorizationInfo authorizationInfo = null;
        try {
            String authorization = request.getHeader("authorization");

            // 从redis获取用户权限信息,直接塞到authorization
            Boolean hasKey = redisTemplate().hasKey(authorization);
            if (hasKey != null && hasKey) {

                authorizationInfo = redisTemplate().opsForValue().get(authorization);
                // 写死一条权限
                List<String> permissionNameList = new ArrayList<>();
                permissionNameList.add("c531dbfe57fb81ab327cc3329e562978");
                if (authorizationInfo == null) {
                    authorizationInfo = new AuthorizationInfo();
                }
                authorizationInfo.addPermissionNames(permissionNameList);
                HttpResult result = new HttpResult<>();
                result.setCode(403);
                result.setInfo("权限不足");
                authorizationInfo.setForbiddenInfo(result);
            }


        }catch (Exception e) {
            throw new AuthorizationException(HttpResult.fail("权限认证失败!"));
        }

        return authorizationInfo;
    }

    @SuppressWarnings("unchecked")
    private RedisTemplate<String,AuthorizationInfo> redisTemplate() {
        return (RedisTemplate<String, AuthorizationInfo>) ApplicationContextUtil.getBean("redisTemplate");
    }
}
